package foxesAndRabbits;
//import static  foxesAndRabbits.Animal.rand;  **Stond er al in

import java.util.List;
import java.util.Random;

/**
 * A class representing shared characteristics of animals.
 * 
 * @author David J. Barnes and Michael Kolling
 * @author Marc Bruins, Michel Jansma and Stephan Veenstra
 * @version 2012.11.08
 */
public abstract class Animal implements Actor
{
	
	// A shared random number generator to control breeding.
    protected static final Random rand = Randomizer.getRandom();
	
    // Whether the animal is alive or not.
    private boolean active;
    // The animal's field.
    private Field field;
    // The animal's position in the field.
    private Location location;
    // The animal's age.
    private int age;
    
    /**
     * Create a new animal at location in field.
     * 
     * @param field The field currently occupied.
     * @param location The location within the field.
     */
    public Animal(boolean randomAge, Field field, Location location)
    {
    	active = true;
        if(randomAge) {
        	setAge(rand.nextInt(getMaxAge()));
        }
        else {
        	setAge(0);
        }
        this.field = field;
        setLocation(location);
        
    }
    
    // ABSTRACT METHODS
    
    /**
     * Make this animal act - that is: make it do
     * whatever it wants/needs to do.
     * @param newAnimals A list to add newly born animals to.
     */
    abstract public void act(List<Actor> newAnimals);
    
    /**
     * Get the animals' max age.
     */
    abstract protected int getMaxAge();
    
    /**
     * Get the animals breeding age.
     */
    abstract protected int getBreedingAge();
    
    abstract protected boolean canBreed();
    
    abstract protected double getBreedingProbability();
    
    abstract protected int getMaxLitterSize();
    
    
    // METHODS

    /**
     * Check whether the animal is alive or not.
     * @return true if the animal is still alive.
     */
    public boolean isActive()
    {
        return active;
    }
    
    /**
     * Generate a number representing the number of births,
     * if it can breed.
     * @return The number of births (may be zero).
     */
    protected int breed()
    {
        int births = 0;
        if(canBreed() && rand.nextDouble() <= getBreedingProbability()) {
            births = rand.nextInt(getMaxLitterSize()) + 1;
        }
        return births;
    }
    
    /**
     * Check whether or not this animal is to give birth at this step.
     * New births will be made into free adjacent locations.
     * @param newAnimals A list to add newly born rabbits to.
     */
    protected void giveBirth(List<Actor> newAnimals)
    {
        // New animals are born into adjacent locations.
        // Get a list of adjacent free locations.
        Field field = getField();
        List<Location> free = field.getFreeAdjacentLocations(getLocation());
        int births = breed();
        for(int b = 0; b < births && free.size() > 0; b++) {
            Location loc = free.remove(0);
            if(this instanceof Falcon){
            	Falcon young = new Falcon(false, field, loc);
            	newAnimals.add(young);
            }
            else if(this instanceof Rabbit){
            	Rabbit young = new Rabbit(false, field, loc);
            	newAnimals.add(young);
            }
            else if(this instanceof Fox){
            	Fox young = new Fox(false, field, loc);
            	newAnimals.add(young);
            }
        }
    }

    /**
     * Returns the age of this animal.
     */
    public int getAge()
    {
    	return this.age;
    }
    
    /**
     * Set the age of this animal.
     */
    public void setAge(int age)
    {
    	this.age = age;
    }
    
    /**
     * Increase the age. This could result in the fox's death.
     */
    protected void incrementAge()
    {
        age++;
        if(age > getMaxAge()) {
            setDead();
        }
    }
    
    /**
     * Indicate that the animal is no longer alive.
     * It is removed from the field.
     */
    public void setDead()
    {
        active = false;
        if(location != null) {
            field.clear(location);
            location = null;
            field = null;
        }
    }

    /**
     * Return the animal's location.
     * @return The animal's location.
     */
    public Location getLocation()
    {
        return location;
    }
    
    /**
     * Return the animal's field.
     * @return The animal's field.
     */
    public Field getField()
    {
        return field;
    }
    
    /**
     * Place the animal at the new location in the given field.
     * @param newLocation The animal's new location.
     */
    public void setLocation(Location newLocation)
    {
        if(location != null) {
            field.clear(location);
        }
        location = newLocation;
        field.place(this, newLocation);
    }
    
}

